/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package mainSystem;

import java.awt.Color;
import java.awt.Frame;
import java.awt.event.*;

import levelSystem.*;
import levelSystem.levels.*;

import tools.*;

public class GameWindow extends Frame implements Runnable{

	private static final long serialVersionUID = 1L;
	private final int fps;
    private volatile boolean quit;
    private int screenWidth;
    private int screenHeight;
    private LevelHandler levelHandler;
    private GameLevel curLevel;
    private Thread animator;
    private String title;
    
    public GameWindow() {
        this("Codinome PACOCA", 780, 600, Constants.DEFAULT_FPS, new MainMenu()); 
    }
    public GameWindow(int w, int h) { 
        this("Codinome PACOCA", w, h, Constants.DEFAULT_FPS, new MainMenu());
    }
    public GameWindow(String title, int w, int h, int f) { 
        this(title, w, h, f, new MainMenu());
    }
    public GameWindow(String title, int w, int h, int f, GameLevel g)
    {
        super(title);
        this.title = title;
        setBackground(Color.black);
        
        setResizable(false);
        addWindowListener(new WindowListener() {
			
			
			public void windowOpened(WindowEvent arg0) {
				if(curLevel != null)curLevel.resumeGame();
				requestFocus();
			}
			
			
			public void windowIconified(WindowEvent arg0) {
				if(curLevel != null)curLevel.pauseGame();
			}
			
			
			public void windowDeiconified(WindowEvent arg0) {
				if(curLevel != null)curLevel.resumeGame();
				requestFocus();
			}
			
			
			public void windowDeactivated(WindowEvent arg0) {
				if(curLevel != null)curLevel.pauseGame();
			}
			
			
            public void windowClosing(WindowEvent e) {
                quit = true;
            }
			
			
			public void windowClosed(WindowEvent arg0) {
			}
			
			
			public void windowActivated(WindowEvent arg0) {
				if(curLevel != null)curLevel.resumeGame();
				requestFocus();
			}
		});
        addWindowFocusListener(new WindowFocusListener() {
			
			
			public void windowLostFocus(WindowEvent arg0) {
				if(curLevel != null) curLevel.pauseGame();
			}
			
			
			public void windowGainedFocus(WindowEvent arg0) {
				if(curLevel != null)curLevel.resumeGame();
			}
		});
        addKeyListener(new GameWindowKeyHandler(this){});
        
        setVisible(true);

        setSize(w + getInsets().left + getInsets().right, 
        		h + getInsets().top + getInsets().bottom);
        setLocationRelativeTo(null);
        
        createBufferStrategy(2);
        
        /* Variaveis de controle */
        quit = false;
        animator = null;
        
        /* Variaveis fisicas */
        screenWidth = w;
        screenHeight = h;
        fps = f;
        
        /* level */
        levelHandler = new LevelHandler(this);
        
        if(g != null) curLevel = g;
        else curLevel = new MainMenu();
        
        curLevel.setLevelHandler(levelHandler);
        curLevel.init();
        
        setFocusable(true);
        requestFocus();
        
        start();
    }
    
    
    private void start()
    {
        if(animator == null)
        {
            animator = new Thread(this);
            animator.start();
        }
    }
    
    private void draw()
    {
        if(!getBufferStrategy().contentsLost())
        {
            getBufferStrategy().show();
        }
    }

    
    public void run() {
        /* Variaveis de controle de tempo */
        final Timer fpsControl = new Timer();
        final long period = 1000000000L/fps;
        long sleepTime = 0L;
        long overTime = 0L;
        int numDelays = 0;
        int skips = 0;
        
        final Timer allTime = new Timer();
        long allFrames = 0L;
        
        if(curLevel == null) quit = true;
        
        allTime.start();
        while(!quit) // enquanto nao sair do jogo
        {
        	if(!curLevel.isPaused())
        	{
        		if(curLevel.isDebugOn())
        		{
		        	allFrames++;
		        	if(allTime.getTime() > 1000000000L){
		        		setTitle("FPS: "+allFrames);
		        		allFrames = 0;
		        		allTime.start();
		        	}
        		}else
        		{
        			setTitle(title);
        		}
        		fpsControl.start(); // iniciar timer para o frame atual
        		
        		if(!curLevel.logic()) quit = true;
        	}
        	curLevel.renderLevel(getBufferStrategy().getDrawGraphics().create(
 				   getInsets().left, getInsets().top,
 				   screenWidth, screenHeight));
            draw();
            
        	if(!curLevel.isPaused())
        	{
	            if(!quit)	            
	            {		            
		            sleepTime = period - fpsControl.getTime();
		            if(sleepTime >= 0) // se o tempo que demorou pra pegar o tempo mais o excesso de tempo 
					 				   // anterior for menor que o periodo, durma o tempo restante
					{
					    sleepTime /= 1000000L; // nano -> mili
					    try {
					        Thread.sleep(sleepTime);
					    } catch (InterruptedException ex) {}
					}
					else
					{
						overTime -= sleepTime;
						if(++numDelays > Constants.MAX_DELAYS)
					 	{
							Thread.yield();
							numDelays = 0;
					 	}
					}
		            
		            while(overTime > period && skips < Constants.MAX_SKIPS && !quit)
		            {
		            	overTime -= period;
		            	skips++;
		            	
		            	if(!curLevel.logic()) quit = true;
		            }
	            }
        	}
        }
        dispose();
        System.exit(0);
    }
    
    public void setCurLevel(GameLevel g)
    {
    	curLevel = g;
    	curLevel.setLevelHandler(levelHandler);
    	curLevel.init();
    }
    public void setCurLevel(GameLevel g, int x, int y)
    {
    	curLevel = g;
    	curLevel.setLevelHandler(levelHandler);
    	curLevel.init(x, y);
    }
    public GameLevel getCurLevel()
    {
    	return curLevel;
    }
    
    public void quit()
    {
    	quit = true;
    }
}
